/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd;

import java.io.IOException;
import java.io.InputStream;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;

import org.zhiqim.kernel.util.Asserts;

/**
 * HTTP阻塞式输入流
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class HttpInputStream extends InputStream
{
    private InputStream input;
    private ByteBuffer buffer;
    
    public HttpInputStream()
    {
    }
    
    public HttpInputStream(InputStream input)
    {
        this.input = input;
    }
    
    /*****************************************************************************/
    //NIO使用的缓冲
    /*****************************************************************************/
    
    /**
     * 增加缓冲数据，检查是否在起始位置，不在会作flip
     * 
     * @param buf   字节缓冲
     */
    public synchronized void addBuffer(ByteBuffer buf)
    {
        Asserts.as(input == null?null:"已有输入流，不支持增加缓冲数据");
        
        if (buf.position() != 0)
        {//新增加的没作flip操作的
            buf.flip();
        }
        
        if (!buf.hasRemaining())
        {//没有数据不处理
            return;
        }
        
        if (buffer == null)
        {
            buffer = ByteBuffer.allocate(buf.remaining());
            buffer.put(buf).flip();
        }
        else
        {
            ByteBuffer nBuf = ByteBuffer.allocate(buffer.remaining() + buf.remaining());
            nBuf.put(buffer).put(buf).flip();
            buffer = nBuf;
        }
    }
    
    public synchronized byte[] read(int len)
    {
        Asserts.as(input == null?null:"已有输入流，不支持该方法调用");
        
        if (buffer == null)
            return new byte[0];
        
        int length = buffer.remaining();
        if (length <= 0)
            return new byte[0];
        
        int count = length <= len?length:len;
        byte[] buf = new byte[count];
        buffer.get(buf);
        return buf;
    }
    
    /*****************************************************************************/
    //NIO/BIO共用的InputStream方法
    /*****************************************************************************/
    
    public synchronized int read() throws IOException
    {
        if (input != null)
            return input.read();
        
        if (buffer == null || !buffer.hasRemaining())
            return -1;
        
        try{return buffer.get();}catch(BufferUnderflowException e){return -1;}
    }
    
    public synchronized int read(byte[] b, int off, int len) throws IOException
    {
        if (input != null)
            return input.read(b, off, len);
        
        if (buffer == null || !buffer.hasRemaining())
            return -1;
        
        int pos = buffer.position();
        buffer.get(b, off, len);
        return buffer.position() - pos;
    }

    public synchronized int read(byte[] b) throws IOException
    {
        if (input != null)
            return input.read(b);
        
        if (buffer == null || !buffer.hasRemaining())
            return -1;
        
        int pos = buffer.position();
        buffer.get(b);
        return buffer.position() - pos;
    }
    
    public synchronized int available()
    {
        if (input != null)
            try{return input.available();}catch(IOException e){throw Asserts.exception(e);}
        
        return buffer==null?-1:buffer.remaining();
    }
}
